package niu.toy.spring.support;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;


public class PropertyHandler {
    private  PropertyDescriptor pd;
    private Object bean;
    public PropertyHandler(Object bean, PropertyDescriptor pd) {
        this.bean=bean;
        this.pd = pd;

    }
    public PropertyHandler(Object bean, String propertyName){
        this.bean=bean;
        try {
            System.out.println("new PropertyDescriptor propertyName="+propertyName+" bean="+bean);
            this.pd = new PropertyDescriptor(propertyName, bean.getClass());
        } catch (IntrospectionException e) {
            e.printStackTrace();
        }
    }
    public Type getType(){
       return pd.getReadMethod().getGenericReturnType();
    }

    public Type getMapKeyType(int nestingLevel) {
        return getGenerics(nested(nestingLevel))[0];
    }

    public Type getMapValueType(int nestingLevel) {
        return getGenerics(nested(nestingLevel))[1];
    }

    public Type getMapValueSubType(int nestingLevel) {
        return getGenerics(getGenerics(nested(nestingLevel))[1])[0];
    }
    public Type getValueSubType(int nestingLevel) {
        return getGenerics(nested(nestingLevel))[0];
    }

    public Type getCollectionType(int nestingLevel) {
        return  getGenerics(nested(nestingLevel))[0];
    }
    public Type  nested(int nestingLevel){
        Type result=getType();
        for (int i = 2; i <= nestingLevel; i++) {
            if (result.getClass().isArray()) {
                result = result.getClass().getComponentType();
            }
            else {
                if (result instanceof ParameterizedType) {
                    Type[] actualTypeArguments = ((ParameterizedType) result).getActualTypeArguments();
                    result = actualTypeArguments[actualTypeArguments.length - 1];
                }else{
                    result=null;
                    break;
                }
            }
        }
        return result;
    }
    public Object getValue() {
        Method getter = pd.getReadMethod();
        try {
            return getter.invoke(this.bean);
        } catch (InvocationTargetException e) {
            throw new BeansException(this.bean.getClass()+"的属性:"+this.pd.getName()+",其getter调用异常",e.getTargetException());
        }catch (Exception ex) {
            throw new BeansException(this.bean.getClass()+"的属性:"+this.pd.getName()+",其getter调用异常", ex.getCause());
        }

    }
    public Type[] getGenerics(Type type) {
        if (type instanceof ParameterizedType) {
            Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
            return actualTypeArguments;
        }else{
            return ArrayUtil.toArray(Arrays.asList(type),Type.class);
        }
    }
    public boolean hasGenerics(Type type) {
        return (getGenerics(type).length > 0);
    }
    public void setValue(Object value) {
       Method setter =  this.pd.getWriteMethod();
       final Class<?>[] parameterTypes = setter.getParameterTypes();
        if (false == parameterTypes[0].isAssignableFrom(value.getClass())) {
            value= Convert.convert(parameterTypes[0], value);
        }
        try {
            setter.invoke(this.bean, value);
        } catch (InvocationTargetException e) {
            throw new BeansException(this.bean.getClass()+"的属性:"+this.pd.getName()+",其setter调用异常",e.getTargetException());
        }catch (Exception ex) {
            throw new BeansException(this.bean.getClass()+"的属性:"+this.pd.getName()+",其setter调用异常", ex.getCause());
        }
    }
}
